package com.android.monee.domain;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.joda.time.DateTime;
import org.joda.time.Months;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import com.android.monee.data.access.DaoFactory;
import com.android.monee.data.access.MensualityDao;
import com.android.monee.data.model.Budget.BudgetState;
import com.android.monee.data.model.Mensuality;

public class MensAccessorMap implements MensAccessor {
	
	private BudgetService budget; 
	private MensualityCalculator mensCalc;
	private List<Mensuality> mensualities;
	private BudgetState refreshBudgetState;
	
	public MensAccessorMap(BudgetService budget){
		this.budget = budget;
		this.mensCalc = new RunningMensCalculator(budget);
	}
	
	public void refresh(){
		refreshBudgetState = budget.getState();
		updateMensCal();
		
		mensualities = new ArrayList<Mensuality>();
		MensualityDao dao = DaoFactory.getMensualityDao();
		mensualities.addAll(dao.findByBudget(budget));
		mensualities.addAll(mensCalc.calcUndoneMensualities());
	}

	@Override
	public List<Mensuality> getAll() {
		if(needsRefresh())
			refresh();
		return mensualities;
	}

	@Override
	public List<Mensuality> getDone(boolean done) {
		if(needsRefresh())
			refresh();
		
		List<Mensuality> res = new ArrayList<Mensuality>();
		for(Mensuality mens : mensualities){
			if(mens.isDone() == done)
				res.add(mens);
		}
		
		return res;
	}
	
	@Override
	public List<Mensuality> getCancelled(boolean cancelled) {
		if(needsRefresh())
			refresh();
		
		List<Mensuality> res = new ArrayList<Mensuality>();
		for(Mensuality mens : mensualities){
			if(mens.isCancelled() == cancelled)
				res.add(mens);
		}
		
		return res;
	}
	
	private boolean needsRefresh(){
		return mensualities == null 
				|| mensualities == null
				|| !budget.getState().equals(refreshBudgetState);
	}
	
	private void updateMensCal(){
		switch(refreshBudgetState){
		case RUNNING:
			this.mensCalc = new RunningMensCalculator(budget);
			break;
		case PAUSED:
			this.mensCalc = new PausedMensCalculator(budget);
			break;
		}
	}

	@Override
	public Mensuality get(Date date) {
		if(needsRefresh())
			refresh();
		
		for(Mensuality mens : mensualities){
			DateTime mensJDate = new DateTime(mens.getDate());
			DateTime jDate = new DateTime(date);
			if(Months.monthsBetween(mensJDate, jDate).getMonths() == 0)
				return mens;
		}
		throw new RuntimeException("Impossible de trouver une mensualité correspondante à la date : "+date);
	}

	@Override
	public Mensuality get(int year, int month) {
		if(needsRefresh())
			refresh();
		
		for(Mensuality mens : mensualities){
			DateTime mensJDate = new DateTime(mens.getDate());
			DateTime jDate = new DateTime(year, month, 1, 0, 0);

			if(Months.monthsBetween(mensJDate, jDate).getMonths() == 0)
				return mens;
		}
		throw new RuntimeException("Impossible de trouver une mensualité correspondante à l'année "+year+" et au mois "+month);
	}

	@Override
	public Mensuality get(DateTime date) {
		if(needsRefresh())
			refresh();
		
		for(Mensuality mens : mensualities){
			DateTime mensJDate = new DateTime(mens.getDate());
			
			if(Months.monthsBetween(mensJDate, date).getMonths() == 0)
				return mens;
		}
		return null;
		//throw new RuntimeException("Impossible de trouver une mensualité correspondante à la date "+date+" pour le budget '"+budget.getName()+"'");
	}

	@Override
	public Mensuality first() {
		if(needsRefresh())
			refresh();
		
		Mensuality first = null;
		if(mensualities.size() > 0)
			first = mensualities.get(0);
		return first;
	}
	
	@Override
	public Mensuality last() {
		if(needsRefresh())
			refresh();
		
		Mensuality last = null;
		int size = mensualities.size();
		if(size > 0)
			last = mensualities.get(size-1);
		return last;
	}
}
